#################################################################################################
# Group Casting Policy
#
# Used to determine if a selected unit or group can "cast" a spell. In other words, will test if
# the action button should show up in the action list. Note that the bVisible variables work
# as they do in all other functions.
#################################################################################################

import CvUtil
from CvPythonExtensions import *
from GerikSpells import GerikSpellBase

# globals
gc = CyGlobalContext()

class GSBase:
    """
    """
    def __init__(self):
        """
        """
        pass
    
    def canUnitCast(self, pCastingUnit, pCastingPlot, bVisible):
        """
        Arguments:
        pCastingUnit: The unit that will be casting the spell.
        pCastingPlot: The plot the unit will be casting the spell on.
        bVisible: True if we're just checking if the button should be visible
                  False if we're checking if the button should be selectable.

        Returns:
        boolean value, depending on if the unit can cast the spell.

        Used to determine if a specific unit can cast a spell (and thus allowing
        the action button to be placed into their list of action buttons when selected).
        """
        raise NotImplementedError

    def canGroupCast(self, pCastingGroup, pCastingPlot, bVisible):
        """
        Arguments:
        pCastingGroup: The CySelectionGroup we are checking if the spell action button should be shown.
        pCastingPlot: The CyPlot object that the CySelectionGroup is trying to cast the spell from.
        bVisible: True if we're just checking if the button should be visible.
                  False if we're checking if the button should be selectable.

        Returns:
        boolean value, depending on if the group can cast the spell.


        Used to determine if the action button for the spell should be placed in the group's list of
        actions available, and if the group can cast that spell. Note that a unit may be able to
        cast a spell but if in a group with units that can't, the button may or may not appear.
        This function determines that.

        This is called from the SDK, so be sure use a policy or override this function yourself.
        """
        raise NotImplementedError


##########################################
#
# Group Policies
#
##########################################

class GSAll(GSBase):
    """
    Whenever a check for a group is made, the function returns true only if all the units in the group
    return true in their canUnitCast function.
    """
    def __init__(self):
        """
        """
        GSBase.__init__(self)

    def canGroupCast(self, pCastingGroup, pCastingPlot, bVisible):
        """
        Arguments:
            pCastingGorup: The group whose ability to cast we are checking.
            pCastingPlot: The plot where we are testing if the group can cast.
            bVisible: The visibility boolean value.
                True: We're just testing if we can see the icon, but not if the group can actually cast.
                False: We are checking both that the icon should be shown and that it should be selectable.

        Returns:
            boolean value on whether or not the spell is visible or castable
        """
        for pUnit in pCastingGroup.getUnits():
            if not self.canUnitCast(pUnit, pCastingPlot, bVisible):
                return False

        return True

# GSAny
# Whenever a check for a group is made, the function returns true if any of the units in the group
# return true in their canUnitCast function.
class GSAny(GSBase):
    def __init__(self):
        """
        """
        GSBase.__init__(self)

    def canGroupCast(self, pCastingGroup, pCastingPlot, bVisible):
        """
        Arguments:
            pCastingGorup: The group whose ability to cast we are checking.
            pCastingPlot: The plot where we are testing if the group can cast.
            bVisible: The visibility boolean value.
                True: We're just testing if we can see the icon, but not if the group can actually cast.
                False: We are checking both that the icon should be shown and that it should be selectable.

        Returns:
            boolean value on whether or not the spell is visible or castable
        """
        for pUnit in pCastingGroup.getUnits():
            if self.canUnitCast(pUnit, pCastingPlot, bVisible):
                return True

        return False

#

class GSQuota(GSBase):
    """
    Whenever a check for a group is made, the function returns true if a certain number of units in the group
    return true in their canUnitCast function. Set the number by using the setGroupPolicyQuota function
    in the constructor.
    """
   
    def __init__(self):
        """
        """
        GSBase.__init__(self)
        self.m_iQuota = 1

    def getGroupPolicyQuota(self):
        """
        Arguments:
            None
        Returns:
            The quota of units needed in the group that can support casting in order to pass the test for casting.
        """
        return self.m_iQuota

    def setGroupPolicyQuota(self, iQuota):
        """
        Arguments:
            iQuota: The quota of units needed in the group that can support casting in order to pass 
                    the test for casting.
        Returns:
            None
        """
        self.m_iQuota = iQuota

    def canGroupCast(self, pCastingGroup, pCastingPlot, bVisible):
        """
        Arguments:
            pCastingGorup: The group whose ability to cast we are checking.
            pCastingPlot: The plot where we are testing if the group can cast.
            bVisible: The visibility boolean value.
                True: We're just testing if we can see the icon, but not if the group can actually cast.
                False: We are checking both that the icon should be shown and that it should be selectable.

        Returns:
            boolean value on whether or not the spell is visible or castable
        """
        iNumPassed = 0
        for pUnit in pCastingGroup.getUnits():
            if self.canUnitCast(pUnit, pCastingPlot, bVisible):
                iNumPassed += 1
                if iNumPassed >= self.m_iQuota:
                    return True

        return False

